# 添加必要的导入
from __future__ import annotations

import pandas as pd
from dash import Input, Output, callback_context
import plotly.graph_objects as go
from dash import Input, Output, State, callback_context, dcc, html ,ALL # 添加dcc和html导入
import dash,os
from datetime import date
from flask_login import current_user
from sqlalchemy import and_, func, cast, Float
import requests.utils  # 添加URL编码支持

from dash.exceptions import PreventUpdate  # 添加PreventUpdate导入
import json 
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from app import dash_app
# 注释掉不存在的模块导入
# from asset_func import *

from models import *
from datetime import datetime

from server import server
import dash_bootstrap_components as dbc
from modules.bigscreen.charts import create_org_equipment_amount_chart
from modules.bigscreen.charts import get_org_running_status_list, create_org_equipment_health_chart
from modules.bigscreen.charts3 import (
    create_repair_count_chart,
    create_maintain_count_chart,
    create_inspection_count_chart
)

def get_products_summary():
    # 统一改为从StatisticsData获取
    from datetime import date
    with server.app_context():
        today = date.today()
        stats = db.session.query(StatisticsData).filter(
            StatisticsData.stat_date == today
        ).all()
        equipment_count = sum([s.equipment_count or 0 for s in stats])
        total_amount = sum([s.total_value or 0 for s in stats])
        return {
            'equipment_count': equipment_count,
            'total_amount': total_amount,
        }
    


def get_org_products_summary():
    # 统一改为从StatisticsData获取
    from datetime import date
    with server.app_context():
        today = date.today()
        stats = db.session.query(StatisticsData).filter(
            StatisticsData.stat_date == today
        ).all()
        org_names = [s.org_shortname_c for s in stats]
        equipment_counts = [s.equipment_count or 0 for s in stats]
        total_amounts = [s.total_value or 0 for s in stats]
        # 按设备数量降序排列
        combined = list(zip(org_names, equipment_counts, total_amounts))
        combined.sort(key=lambda x: x[1], reverse=True)
        if combined:
            org_names, equipment_counts, total_amounts = zip(*combined)
        else:
            org_names, equipment_counts, total_amounts = [], [], []
        return list(org_names), list(equipment_counts), list(total_amounts)
    

def create_org_equipment_amount_panel():
    summary = get_products_summary()
    total_count = summary['equipment_count']
    total_amount = summary['total_amount']
    title_text = f"设备总数：{total_count}台    总金额：¥{total_amount:.2f}万"
    return html.Div([
        html.Div(title_text, className="panel-title", style={"color": "#33a0ff", "fontSize": "14px", "padding": "5px 10px"}),
        dcc.Graph(
            figure=create_org_equipment_amount_chart(org_names, equipment_counts, total_amounts),
            config={'displayModeBar': False},
            style={"height": "380px"}
        )
    ], className="dashboard-panel", style={"margin": "10px 0", "background": "rgba(0,20,40,0.95)", "borderRadius": "10px", "boxShadow": "0 0 16px #1a4a7a"})

def get_org_equipment_amount_number(org_names, equipment_counts, total_amounts):
    # 统一改为从StatisticsData获取最新日期的数据
    with server.app_context():
        # 查询最新日期
        latest_date_row = db.session.query(func.max(StatisticsData.stat_date)).scalar()

        if latest_date_row is None:
            return {
                'equipment_count': 0,
                'total_amount': 0,
            }

        # 查询最新日期的数据
        stats = db.session.query(StatisticsData).filter(
            StatisticsData.stat_date == latest_date_row
        ).all()

        equipment_count = sum([s.equipment_count or 0 for s in stats])
        total_amount = sum([s.total_value or 0 for s in stats])
        return {
            'equipment_count': equipment_count,
            'total_amount': total_amount,
        }


def register_callbacks(dash_app):
    """注册设备统计相关的回调函数"""
    

    
    dash_app.clientside_callback(
        """
        function(n_intervals) {
            // 获取地图容器尺寸
            var mapContainer = document.getElementById('static-map-container');
            var mapImage = document.getElementById('map-image');
            
            if (!mapContainer || !mapImage) return {};
            
            // 获取实际地图图片尺寸和位置
            var imgWidth = mapImage.clientWidth;
            var imgHeight = mapImage.clientHeight;
            var imgLeft = (mapContainer.clientWidth - imgWidth) / 2;
            var imgTop = (mapContainer.clientHeight - imgHeight) / 2;
            
            // 更新覆盖层样式
            var overlay = document.getElementById('map-overlay');
            if (overlay) {
                // 调整覆盖层大小和位置，使其与地图图片完全重叠
                return {
                    "position": "absolute",
                    "top": imgTop + "px",
                    "left": imgLeft + "px",
                    "width": imgWidth + "px",
                    "height": imgHeight + "px",
                    "pointerEvents": "none"
                };
            }
            
            return {};
        }
        """,
        Output('map-overlay', 'style'),
        [Input('interval-component', 'n_intervals')],
        prevent_initial_call=True
    )


    # 添加地图覆盖层回调
    @dash_app.callback(
        Output('map-overlay', 'children'),
        [
            # Input('interval-component', 'n_intervals'),
            Input('filter-equipment-category', 'value'),
            Input('filter-price-range', 'value')
        ]
    )
    def update_map_overlay( equipment_category, price_range):
        # 医院位置（坐标是相对于地图图片的百分比位置）
        hospital_locations = [
            ["南京东路", 34, 26],
            ["外滩", 52, 22],
            ["豫园", 55, 36],
            ["小东门", 75, 50],
            ["老西门", 56, 50],
            ["打浦桥", 30, 64],
            ["半淞园", 60, 65],
            ["淮海中路", 37, 48],
            ["瑞金二路", 21, 50],
            ["顺昌", 42, 60],
            ["五里桥", 38, 78]
        ]

        # 用excel数据替换数据库查询
        hospital_stats = get_hospital_stats_from_excel(equipment_category, price_range)

        hospital_data = []
        for name, x, y in hospital_locations:
            # excel文件名需与医院简称一致
            count, amount = hospital_stats.get(name, (0, 0))
            hospital_data.append([name, x, y, count, int(amount)])  # 只保留整数

        # 生成圆圈和文本（保持原逻辑）
        circles = []
        for name, x, y, count, amount in hospital_data:
            circles.append(
                html.Div([
                    html.Div(
                        id={'type': 'hospital-circle', 'org_name': name},
                        n_clicks=0,
                        style={
                            "width": "4vw",
                            "height": "4vw",
                            "minWidth": "40px",
                            "minHeight": "40px",
                            "maxWidth": "60px",
                            "maxHeight": "60px",
                            "borderRadius": "50%",
                            "backgroundColor": "rgba(51, 160, 255, 0.6)",
                            "border": "2px solid #33a0ff",
                            "display": "flex",
                            "flexDirection": "column",
                            "justifyContent": "center",
                            "alignItems": "center",
                            "color": "white",
                            "fontSize": "calc(0.8vw + 4px)",
                            "boxShadow": "0 0 10px rgba(51, 160, 255, 0.8)",
                            "animation": "pulse 5s infinite ease-in-out" # 添加这一行应用动画
                        },
                        children=[
                            html.Div(f"{count}台", style={"fontWeight": "bold"}),
                            html.Div(f"{amount}万", style={"fontSize": "calc(0.6vw + 3px)"})  # 只显示整数
                        ]
                    ),
                    html.Div(
                        name,
                        style={
                            "color": "white",
                            "fontSize": "12px",
                            "marginTop": "5px",
                            "textShadow": "0 0 3px #000",
                            "fontWeight": "bold"
                        }
                    )
                ], style={
                    "position": "absolute",
                    "left": f"{x}%",
                    "top": f"{y}%",
                    "transform": "translate(-50%, -50%)",
                    "textAlign": "center",
                    "pointerEvents": "auto",
                    "cursor": "pointer"
                })
            )

        return circles

        

    @dash_app.callback(
        [Output('equipment-count-display', 'children'),
        Output('total-amount-display', 'children')],
        [Input('interval-component', 'n_intervals')]
    )
    def update_product_summary(n_intervals):
        """更新设备总数和金额总值显示"""
        summary = get_products_summary()
        return f"{summary['equipment_count']}台", f"¥{summary['total_amount']:.2f}万"
    
    # 可以保留此回调函数，但界面上不再显示相应元素
    @dash_app.callback(
        Output('equipment-stats-update-time', 'children'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_stats_time(n_intervals):
        """更新统计数据的时间戳"""
        now = datetime.now()
        return f"更新时间: {now.strftime('%Y-%m-%d %H:%M:%S')}"



    @dash_app.callback(
        Output('org-equipment-health-chart', 'figure'),
        Input('interval-component', 'n_intervals')
    )
    def update_org_equipment_health_chart(n):
        running_status_list = get_org_running_status_list()
        return create_org_equipment_health_chart(running_status_list)

    # 新增：图表定时刷新
    @dash_app.callback(
        Output('org-equipment-repaire-count-chart', 'figure'),
        Input('interval-component', 'n_intervals')
    )
    def update_repair_count_chart(n):
        # print("callback2 p465 定时更新已执行 update_repair_count_chart")
        return create_repair_count_chart()

    @dash_app.callback(
        Output('org-equipment-maintain-count-chart', 'figure'),
        Input('interval-component', 'n_intervals')
    )
    def update_maintain_count_chart(n):
        # print("callback2 p473 定时更新已执行 update_maintain_count_chart")
        return create_maintain_count_chart()

    @dash_app.callback(
        Output('org-equipment-inspection-count-chart', 'figure'),
        Input('interval-component', 'n_intervals')
    )
    def update_inspection_count_chart(n):
        # print("callback2 p481 定时更新已执行 update_inspection_count_chart")
        return create_inspection_count_chart()


    @dash_app.callback(
        Output('filter-equipment-category', 'options'),
        [Input('interval-component', 'n_intervals')]
    )
    def update_equipment_category_options(n):
        with server.app_context():
            categories = db.session.query(Product.equipment_category).filter(Product.is_active==True).distinct()
            options = [{'label': c.equipment_category, 'value': c.equipment_category} for c in categories if c.equipment_category]
            return [{'label': '全部分类', 'value': None}] + options




    def get_hospital_stats_from_excel(equipment_category=None, price_range=None):
        stats_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "statistic","xlsx"))
        # print(f"[调试] stats_dir: {stats_dir}")
        # print(f"[调试] equipment_category: {equipment_category}, price_range: {price_range}")
        result = {}
        for fname in os.listdir(stats_dir):
            if fname.endswith(".xlsx"):

                org_name = fname.split("_")[0]
                fpath = os.path.join(stats_dir, fname)
                # print(f"[调试] 正在处理文件: {fpath}")
                try:
                    # Read from the correct sheet name
                    df = pd.read_excel(fpath, sheet_name="设备分类及价格区间统计")
                    # print(f"[调试]org_name= {org_name} 原始数据行数: {len(df)}")

                    # 只保留最新日期的数据
                    if not df.empty and "日期" in df.columns:
                        # Ensure '日期' column is datetime type for proper comparison
                        df["日期"] = pd.to_datetime(df["日期"])
                        latest_date = df["日期"].max()
                        df = df[df["日期"] == latest_date]
                        # print(f"[调试] {org_name} 最新日期: {latest_date.strftime('%Y-%m-%d')}，筛选后行数: {len(df)}")
                    else:
                        print(f"[调试] {org_name} 没有日期列或数据为空")
                        result[org_name] = (0, 0) # Default to 0 if no data
                        continue

                    count = 0
                    amount = 0.0

                    # Separate category data and total row
                    total_row_df = df[df['设备分类'] == '合计数据']
                    df_categories = df[df['设备分类'] != '合计数据'].copy() # Dataframe without total row


                    if equipment_category is not None and equipment_category != '':
                        # Filter by equipment category
                        category_df = df_categories[df_categories["设备分类"] == equipment_category]

                        if not category_df.empty:
                            if price_range is not None and price_range != '':
                                # Filter by both category and price range
                                count_col = f'{price_range}_台数'
                                amount_col = f'{price_range}_金额'
                                if count_col in category_df.columns and amount_col in category_df.columns:
                                    count = int(category_df[count_col].sum()) # Use sum in case of multiple rows (shouldn't happen for category)
                                    amount = float(category_df[amount_col].sum())
                                    # print(f"[调试] {org_name} 按分类 '{equipment_category}' 和价格区间 '{price_range}' 统计结果 台数: {count}, 金额: {amount}")
                                else:
                                     print(f"[调试] {org_name} Excel中没有价格区间列 '{price_range}' 的台数或金额数据")
                                     pass # count and amount remain 0
                            else:
                                # Filter only by equipment category, use total for that category
                                # Use '合计台数' and '合计金额(万元)' for the selected category
                                count = int(category_df["合计台数"].sum())
                                amount = float(category_df["合计金额(万元)"].sum())
                                # print(f"[调试] {org_name} 按分类 '{equipment_category}' 统计结果 台数: {count}, 金额: {amount}")
                        else:
                             # print(f"[调试] {org_name} 分类 '{equipment_category}' 无数据")
                             pass # count and amount remain 0

                    elif price_range is not None and price_range != '':
                         # Filter only by price range (across all categories)
                         count_col = f'{price_range}_台数'
                         amount_col = f'{price_range}_金额'
                         if count_col in df_categories.columns and amount_col in df_categories.columns:
                             # Sum the count and amount in the specified price range columns across all categories
                             count = int(df_categories[count_col].sum())
                             amount = float(df_categories[amount_col].sum())
                             # print(f"[调试] {org_name} 按价格区间 '{price_range}' 统计结果 台数: {count}, 金额: {amount}")
                         else:
                             print(f"[调试] {org_name} Excel中没有价格区间列 '{price_range}' 的台数或金额数据")
                             pass # count and amount remain 0

                    else:
                        # No filter selected, use the total row
                        if not total_row_df.empty:
                            count = int(total_row_df['合计台数'].values[0])
                            amount = float(total_row_df['合计金额(万元)'].values[0])
                            # print(f"[调试] {org_name} 无筛选，使用合计数据 台数: {count}, 金额: {amount}")
                        else:
                            print(f"[调试] {org_name} Excel中没有合计数据行")
                            pass # count and amount remain 0


                    result[org_name] = (count, amount)

                except FileNotFoundError:
                    print(f"[调试] 文件未找到: {fpath}")
                    result[org_name] = (0, 0) # Default to 0 if file not found
                except Exception as e:
                    print(f"[调试] 读取或处理文件 {fname} 失败: {e}")
                    result[org_name] = (0, 0) # Default to 0 on error

        # print(f"callbacks2 p360 [调试] Excel读取结果: {result}")
        return result








    # 处理地图圆圈点击跳转的客户端回调
    dash_app.clientside_callback(
        """
        function(n_clicks_list, circle_ids_state, equipment_category, price_range) {
            const ctx = dash_clientside.callback_context;
            console.log("[DEBUG] clientside_callback triggered");
            console.log("[DEBUG] n_clicks_list:", n_clicks_list);
            console.log("[DEBUG] ctx.triggered:", ctx.triggered);

            if (!ctx.triggered || !ctx.triggered[0] || !n_clicks_list) {
                console.log("[DEBUG] No valid trigger or n_clicks_list is null");
                return window.dash_clientside.no_update;
            }

            // 新增：只有有 n_clicks > 0 的圆圈才跳转
            let clickedIndex = n_clicks_list.findIndex(x => x > 0);
            if (clickedIndex === -1) {
                console.log("[DEBUG] No circle actually clicked, not redirecting.");
                return window.dash_clientside.no_update;
            }

            let clicked_prop_id_str = ctx.triggered[0].prop_id;
            console.log("[DEBUG] clicked_prop_id_str:", clicked_prop_id_str);
            let clicked_id_str = clicked_prop_id_str.split('.')[0];
            let hospital_name = "";

            try {
                const clicked_id_obj = JSON.parse(clicked_id_str);
                console.log("[DEBUG] clicked_id_obj:", clicked_id_obj);
                if (clicked_id_obj && clicked_id_obj.type === 'hospital-circle' && clicked_id_obj.org_name) {
                    hospital_name = clicked_id_obj.org_name;
                }
            } catch (e) {
                console.error("[DEBUG] Error parsing clicked circle ID:", clicked_id_str, e);
                return window.dash_clientside.no_update;
            }
            
            if (hospital_name) {
                // 修改这里的参数名为 org
                let url = `/dash/equipment?org=${encodeURIComponent(hospital_name)}`;
                if (equipment_category !== null && equipment_category !== undefined && equipment_category !== '') {
                    url += `&equipment_category=${encodeURIComponent(equipment_category)}`;
                }
                if (price_range !== null && price_range !== undefined && price_range !== '') {
                    url += `&price_range=${encodeURIComponent(price_range)}`;
                }
                console.log("[DEBUG] Redirecting to: " + url);
                window.location.href = url; // 执行跳转
            }
            // 即使不跳转，也返回 no_update，因为 Output 是一个虚拟组件的数据
            return window.dash_clientside.no_update;
        }
        """,
        Output('dummy-redirect-output', 'data'), 
        [Input({'type': 'hospital-circle', 'org_name': ALL}, 'n_clicks')], 
        [State({'type': 'hospital-circle', 'org_name': ALL}, 'id'), 
         State('filter-equipment-category', 'value'),
         State('filter-price-range', 'value')]
    )


